package lpg;

import java.util.List;
import lpg.util.Utility;

public enum OptionEnum
{
    ACTION_BLOCK("=(string,string,string)")
    {
        int setValue(char[] param, int start, int end, int p, int q, Option option)
        {
            return setTripletValue(param, start, end, q, option, name(), option.actionOptions);
        }
    },

    AST_DIRECTORY("=string")
    {
        int setValue(char[] param, int start, int end, int p, int q, Option option)
        {
            option.astDirectory = option.getStringValue(param, q, end);
            option.astDirectoryLocation = option.getTokenLocation(start, option.tail - start);
            return option.tail;
        }
    },

    AST_TYPE("=string")
    {
        int setValue(char[] param, int start, int end, int p, int q, Option option)
        {
            option.astType = option.getStringValue(param, q, end);
            return option.tail;
        }
    },

    ATTRIBUTES
    {
        int setBooleanValue(boolean flag, int p, Option option)
        {
            option.attributes = flag;
            return p;
        }
    },

    AUTOMATIC_AST("[=<none|nested|toplevel>]")
    {
        int setBooleanValue(boolean flag, int p, Option option)
        {
            option.automaticAst = flag ? Option.AutomaticAst.NESTED : Option.AutomaticAst.NONE;
            return p;
        }

        int setValue(char[] param, int start, int end, int p, int q, Option option)
        {
            String value = option.getStringValue(param, q, end);
            int length = value.length();
            if (length > 1)
            {
                String upperCaseValue = value.toUpperCase();
                if ("NONE".startsWith(upperCaseValue))
                    option.automaticAst = Option.AutomaticAst.NONE;
                else if ("NESTED".startsWith(upperCaseValue))
                    option.automaticAst = Option.AutomaticAst.NESTED;
                else if ("TOPLEVEL".startsWith(upperCaseValue))
                    option.automaticAst = Option.AutomaticAst.TOPLEVEL;
                else
                    option.invalidValueError(param, start, value, p - start);
            }
            else if (length == 1)
            {
                char c = value.charAt(0);
                if (c == 'N' || c == 'n')
                    option.reportAmbiguousOption(param, start, end, true, "NESTED, NONE");
                else if (c == 'T' || c == 't')
                    option.automaticAst = Option.AutomaticAst.TOPLEVEL;
                else
                    option.invalidValueError(param, start, value, p - start);
            }
            else
            {
                option.reportMissingValue(param, start, end);
            }
            return option.tail;
        }
    },

    BACKTRACK
    {
        int setBooleanValue(boolean flag, int p, Option option)
        {
            option.backtrack = flag;
            return p;
        }
    },

    BYTE
    {
        int setBooleanValue(boolean flag, int p, Option option)
        {
            option.byteFlag = flag;
            return p;
        }
    },

    CONFLICTS
    {
        int setBooleanValue(boolean flag, int p, Option option)
        {
            option.conflicts = flag;
            return p;
        }
    },

    DAT_DIRECTORY("=string")
    {
        int setValue(char[] param, int start, int end, int p, int q, Option option)
        {
            option.datDirectory = option.getStringValue(param, q, end);
            option.datDirectoryLocation = option.getTokenLocation(start, option.tail - start);
            return option.tail;
        }
    },

    DAT_FILE("=string")
    {
        int setValue(char[] param, int start, int end, int p, int q, Option option)
        {
            option.datFile = option.getStringValue(param, q, end);
            return option.tail;
        }
    },

    DCL_FILE("=string")
    {
        int setValue(char[] param, int start, int end, int p, int q, Option option)
        {
            option.dclFile = option.getStringValue(param, q, end);
            return option.tail;
        }
    },

    DEBUG
    {
        int setBooleanValue(boolean flag, int p, Option option)
        {
            option.debug = flag;
            return p;
        }
    },

    DEF_FILE("=string")
    {
        int setValue(char[] param, int start, int end, int p, int q, Option option)
        {
            option.defFile = option.getStringValue(param, q, end);
            return option.tail;
        }
    },

    DIRECTORY_PREFIX("=string")
    {
        int setValue(char[] param, int start, int end, int p, int q, Option option)
        {
            option.directoryPrefix = option.getStringValue(param, q, end);
            return option.tail;
        }
    },

    EDIT
    {
        int setBooleanValue(boolean flag, int p, Option option)
        {
            option.edit = flag;
            return p;
        }
    },

    ERROR_MAPS
    {
        int setBooleanValue(boolean flag, int p, Option option)
        {
            option.errorMaps = flag;
            return p;
        }
    },

    ESCAPE("=character")
    {
        int setValue(char[] param, int start, int end, int p, int q, Option option)
        {
            String escape = option.getStringValue(param, q, end);
            if (escape.length() == 1)
            {
                option.escape = escape.charAt(0);
                option.escapeLocation = option.getTokenLocation(start, option.tail - start);
            }
            else // more than a single character
            {
                option.invalidValueError(param, start, escape, p - start);
            }
            return option.tail;
        }
    },

    EXPORT_TERMINALS("=string")
    {
        int setValue(char[] param, int start, int end, int p, int q, Option option)
        {
            int tail;
            if (q < end)
            {
                if (param[q] != '(') // just the file name is provided.
                {
                    option.expFile = option.getStringValue(param, q, end);
                    return option.tail;
                }
                // a parenthesized list of 1, 2 or three arguments: (filename[,prefix[,suffix]])
                option.expFile = option.getStringValue(param, q + 1, end);
                tail = Option.cleanUp(param, option.tail, end);
                if (tail < end)
                {
                    if (param[tail] == ')')
                        return tail + 1;

                    option.expPrefix = option.getStringValue(param, tail, end);
                    tail = Option.cleanUp(param, option.tail, end);
                    if (tail < end)
                    {
                        if (param[tail] == ')')
                            return tail + 1;

                        option.expSuffix = option.getStringValue(param, tail, end);
                        tail = Option.cleanUp(param, option.tail, end);
                        if (tail < end && param[tail] == ')')
                            return tail + 1;
                    }
                }
            }
            else
            {
                tail = Option.advancePastOption(param, start, end);
            }

            option.invalidTripletValueError(param, start, tail - start,
                    name(), "(filename[,prefix[,suffix]])");
            return tail;
        }
    },

    EXTENDS_PARSETABLE("[=string]")
    {
        int setBooleanValue(boolean flag, int p, Option option)
        {
            if (flag)
                option.extendsParsetable = "";
            return p;
        }

        int setValue(char[] param, int start, int end, int p, int q, Option option)
        {
            option.extendsParsetable = option.getStringValue(param, q, end);
            return option.tail;
        }
    },

    FACTORY("=string")
    {
        int setValue(char[] param, int start, int end, int p, int q, Option option)
        {
            option.factory = option.getStringValue(param, q, end);
            return option.tail;
        }
    },

    FILE_PREFIX("=string")
    {
        int setValue(char[] param, int start, int end, int p, int q, Option option)
        {
            option.filePrefix = option.getStringValue(param, q, end);
            return option.tail;
        }
    },

    FILTER("=string")
    {
        int setValue(char[] param, int start, int end, int p, int q, Option option)
        {
            option.filter = option.getStringValue(param, q, end);
            Option.processPath(option.filterFile, option.filter);
            return option.tail;
        }
    },

    FIRST
    {
        int setBooleanValue(boolean flag, int p, Option option)
        {
            option.first = flag;
            return p;
        }
    },

    FOLLOW
    {
        int setBooleanValue(boolean flag, int p, Option option)
        {
            option.follow = flag;
            return p;
        }
    },

    GLR
    {
        int setBooleanValue(boolean flag, int p, Option option)
        {
            option.glr = flag;
            return p;
        }
    },

    GOTO_DEFAULT
    {
        int setBooleanValue(boolean flag, int p, Option option)
        {
            option.gotoDefault = flag;
            return p;
        }
    },

    HEADERS("=(string,string,string)")
    {
        int setValue(char[] param, int start, int end, int p, int q, Option option)
        {
            return setTripletValue(param, start, end, q, option, name(), option.headerOptions);
        }
    },

    IGNORE_BLOCK("=string")
    {
        int setValue(char[] param, int start, int end, int p, int q, Option option)
        {
            String ignoreBlock = option.getStringValue(param, q, end);
            option.actionBlocks.findOrInsertIgnoredBlock(ignoreBlock);
            return option.tail;
        }
    },

    IMP_FILE("=string")
    {
        int setValue(char[] param, int start, int end, int p, int q, Option option)
        {
            option.impFile = option.getStringValue(param, q, end);
            return option.tail;
        }
    },

    IMPORT_TERMINALS("=string")
    {
        int setValue(char[] param, int start, int end, int p, int q, Option option)
        {
            option.importTerminals = option.getStringValue(param, q, end);
            Option.processPath(option.importFile, option.importTerminals);
            return option.tail;
        }
    },

    INCLUDE_DIRECTORIES("=string", 2)
    {
        int setValue(char[] param, int start, int end, int p, int q, Option option)
        {
            option.includeDirectory = option.getStringValue(param, q, end);
            return option.tail;
        }
    },

    INCLUDE_DIRECTORY("=string")
    {
        int setValue(char[] param, int start, int end, int p, int q, Option option)
        {
            option.includeDirectory = option.getStringValue(param, q, end);
            Option.processPath(option.includeSearchDirectory, option.includeDirectory, option.homeDirectory);
            return option.tail;
        }
    },

    LALR("[=integer]")
    {
        int setBooleanValue(boolean flag, int p, Option option)
        {
            option.lalrLevel = 1;
            option.slr = !flag;
            return p;
        }

        int setValue(char[] param, int start, int end, int p, int q, Option option)
        {
            String value = option.getValue(param, q, end);
            try
            {
                option.slr = false;
                option.lalrLevel = Integer.parseInt(value);
                if (option.lalrLevel < 0)
                    option.invalidValueError(param, start, value, p - start);
            }
            catch (NumberFormatException e)
            {
                option.invalidValueError(param, start, value, p - start);
            }
            return option.tail;
        }
    },

    LEGACY
    {
        int setBooleanValue(boolean flag, int p, Option option)
        {
            option.legacy = flag;
            return p;
        }
    },

    LIST
    {
        int setBooleanValue(boolean flag, int p, Option option)
        {
            option.list = flag;
            return p;
        }
    },

    MARGIN("=integer")
    {
        int setValue(char[] param, int start, int end, int p, int q, Option option)
        {
            String value = option.getValue(param, q, end);
            try
            {
                option.margin = Integer.parseInt(value);
                if (option.margin < 0)
                    option.invalidValueError(param, start, value, p - start);
            }
            catch (NumberFormatException e)
            {
                option.invalidValueError(param, start, value, p - start);
            }
            return option.tail;
        }
    },

    MAX_CASES("=integer")
    {
        int setValue(char[] param, int start, int end, int p, int q, Option option)
        {
            String value = option.getValue(param, q, end);
            try
            {
                option.maxCases = Integer.parseInt(value);
                if (option.maxCases < 0)
                    option.invalidValueError(param, start, value, p - start);
            }
            catch (NumberFormatException e)
            {
                option.invalidValueError(param, start, value, p - start);
            }
            return option.tail;
        }
    },

    NAMES("=<optimized|maximum|minimum>")
    {
        int setValue(char[] param, int start, int end, int p, int q, Option option)
        {
            String value = option.getStringValue(param, q, end);
            int length = value.length();
            if (length > 1)
            {
                String upperCaseValue = value.toUpperCase();
                if ("OPTIMIZED".startsWith(upperCaseValue))
                    option.names = Option.Names.OPTIMIZED;
                else if ("MAXIMUM".startsWith(upperCaseValue))
                    option.names = Option.Names.MAXIMUM;
                else if ("MINIMUM".startsWith(upperCaseValue))
                    option.names = Option.Names.MINIMUM;
                else
                    option.invalidValueError(param, start, value, p - start);
            }
            else if (length == 1)
            {
                char c = value.charAt(0);
                if (c == 'M' || c == 'm')
                    option.reportAmbiguousOption(param, start, end, true, "MAXIMUM, MINIMUM");
                else if (c == 'O' || c == 'o')
                    option.names = Option.Names.OPTIMIZED;
                else
                    option.invalidValueError(param, start, value, p - start);
            }
            else
            {
                option.reportMissingValue(param, start, end);
            }
            return option.tail;
        }
    },

    NT_CHECK
    {
        int setBooleanValue(boolean flag, int p, Option option)
        {
            option.ntCheck = flag;
            return p;
        }
    },

    OR_MARKER("=character")
    {
        int setValue(char[] param, int start, int end, int p, int q, Option option)
        {
            String orMarker = option.getStringValue(param, q, end);
            if (orMarker.length() == 1)
            {
                option.orMarker = orMarker.charAt(0);
                option.orMarkerLocation = option.getTokenLocation(start, option.tail - start);
            }
            else // more than a single character
            {
                option.invalidValueError(param, start, orMarker, p - start);
            }
            return option.tail;
        }
    },

    OUT_DIRECTORY("=string")
    {
        int setValue(char[] param, int start, int end, int p, int q, Option option)
        {
            option.outDirectory = option.getStringValue(param, q, end);
            option.outDirectoryLocation = option.getTokenLocation(start, option.tail - start);
            return option.tail;
        }
    },

    PACKAGE("=string")
    {
        int setValue(char[] param, int start, int end, int p, int q, Option option)
        {
            option.packageName = option.getStringValue(param, q, end);
            if (option.packageName.length() > 0 &&
                    Utility.checkQualifiedIdentifier(option.packageName) < 0)
            {
                option.invalidValueError(param, start, option.packageName, p - start);
            }
            return option.tail;
        }
    },

    PARENT_SAVED
    {
        int setBooleanValue(boolean flag, int p, Option option)
        {
            option.parentSaved = flag;
            return p;
        }
    },

    PARSETABLE_INTERFACES("[=string]")
    {
        int setBooleanValue(boolean flag, int p, Option option)
        {
            if (flag)
                option.parsetableInterfaces = "";
            return p;
        }

        int setValue(char[] param, int start, int end, int p, int q, Option option)
        {
            option.parsetableInterfaces = option.getStringValue(param, q, end);
            return option.tail;
        }

    },

    PREFIX("=string")
    {
        int setValue(char[] param, int start, int end, int p, int q, Option option)
        {
            option.prefix = option.getStringValue(param, q, end);
            return option.tail;
        }
    },

    PRIORITY
    {
        int setBooleanValue(boolean flag, int p, Option option)
        {
            option.priority = flag;
            return p;
        }
    },

    PROGRAMMING_LANGUAGE("=<none|xml|c|cpp|c++|java|plx|plxasm|ml>")
    {
        int setValue(char[] param, int start, int end, int p, int q, Option option)
        {
            String value = option.getStringValue(param, q, end);
            int length = value.length();
            if (length > 0)
            {
                String upperCaseValue = value.toUpperCase();
                if ("NONE".startsWith(upperCaseValue) || "XML".startsWith(upperCaseValue))
                    option.programmingLanguage = Option.ProgrammingLanguage.XML;
                else if ("C".equals(upperCaseValue))
                    option.programmingLanguage = Option.ProgrammingLanguage.C;
                else if ("CPP".startsWith(upperCaseValue) || "C++".startsWith(upperCaseValue))
                    option.programmingLanguage = Option.ProgrammingLanguage.CPP;
                else if ("JAVA".startsWith(upperCaseValue))
                    option.programmingLanguage = Option.ProgrammingLanguage.JAVA;
                else if ("PLX".startsWith(upperCaseValue))
                    option.programmingLanguage = Option.ProgrammingLanguage.PLX;
                else if ("PLXASM".startsWith(upperCaseValue))
                    option.programmingLanguage = Option.ProgrammingLanguage.PLXASM;
                else if ("ML".startsWith(upperCaseValue))
                    option.programmingLanguage = Option.ProgrammingLanguage.ML;
                else
                    option.invalidValueError(param, start, value, p - start);
            }
            else
            {
                option.reportMissingValue(param, start, end);
            }
            return option.tail;
        }
    },

    PROSTHESES("=<optimized|maximum|minimum>")
    {
        int setValue(char[] param, int start, int end, int p, int q, Option option)
        {
            return setProsthesesValue(param, start, end, p, q, option);
        }
    },

    PROSTHESIS("=<optimized|maximum|minimum>", 2)
    {
        int setValue(char[] param, int start, int end, int p, int q, Option option)
        {
            return setProsthesesValue(param, start, end, p, q, option);
        }
    },

    PRS_FILE("=string")
    {
        int setValue(char[] param, int start, int end, int p, int q, Option option)
        {
            option.prsFile = option.getStringValue(param, q, end);
            return option.tail;
        }
    },

    QUIET
    {
        int setBooleanValue(boolean flag, int p, Option option)
        {
            option.quiet = flag;
            return p;
        }
    },

    READ_REDUCE
    {
        int setBooleanValue(boolean flag, int p, Option option)
        {
            option.readReduce = flag;
            return p;
        }
    },

    REMAP_TERMINALS
    {
        int setBooleanValue(boolean flag, int p, Option option)
        {
            option.remapTerminals = flag;
            return p;
        }
    },

    SCOPES
    {
        int setBooleanValue(boolean flag, int p, Option option)
        {
            option.scopes = flag;
            return p;
        }
    },

    SERIALIZE
    {
        int setBooleanValue(boolean flag, int p, Option option)
        {
            option.serialize = flag;
            return p;
        }
    },

    SHIFT_DEFAULT
    {
        int setBooleanValue(boolean flag, int p, Option option)
        {
            option.shiftDefault = flag;
            return p;
        }
    },

    SINGLE_PRODUCTIONS
    {
        int setBooleanValue(boolean flag, int p, Option option)
        {
            option.singleProductions = flag;
            return p;
        }
    },

    SLR
    {
        int setBooleanValue(boolean flag, int p, Option option)
        {
            option.slr = flag;
            return p;
        }
    },

    SOFT_KEYWORDS
    {
        int setBooleanValue(boolean flag, int p, Option option)
        {
            option.softKeywords = flag;
            return p;
        }
    },

    STATES
    {
        int setBooleanValue(boolean flag, int p, Option option)
        {
            option.states = flag;
            return p;
        }
    },

    SUFFIX("=string")
    {
        int setValue(char[] param, int start, int end, int p, int q, Option option)
        {
            option.suffix = option.getStringValue(param, q, end);
            return option.tail;
        }
    },

    SYM_FILE("=string")
    {
        int setValue(char[] param, int start, int end, int p, int q, Option option)
        {
            option.symFile = option.getStringValue(param, q, end);
            return option.tail;
        }
    },

    TAB_FILE("=string")
    {
        int setValue(char[] param, int start, int end, int p, int q, Option option)
        {
            option.tabFile = option.getStringValue(param, q, end);
            return option.tail;
        }
    },

    TABLE("[=<none|xml|c|cpp|c++|java|plx|plxasm|ml>]")
    {
        int setBooleanValue(boolean flag, int p, Option option)
        {
            option.table = flag;
            return p;
        }

        int setValue(char[] param, int start, int end, int p, int q, Option option)
        {
            option.table = true;

            String value = option.getStringValue(param, q, end);
            int length = value.length();
            if (length > 0)
            {
                String upperCaseValue = value.toUpperCase();
                if ("NONE".startsWith(upperCaseValue))
                {
                    option.table = false;
                    option.programmingLanguage = Option.ProgrammingLanguage.XML;
                }
                else if ("XML".startsWith(upperCaseValue))
                    option.programmingLanguage = Option.ProgrammingLanguage.XML;
                else if ("C".equals(upperCaseValue))
                    option.programmingLanguage = Option.ProgrammingLanguage.C;
                else if ("CPP".startsWith(upperCaseValue) || "C++".startsWith(upperCaseValue))
                    option.programmingLanguage = Option.ProgrammingLanguage.CPP;
                else if ("JAVA".startsWith(upperCaseValue))
                    option.programmingLanguage = Option.ProgrammingLanguage.JAVA;
                else if ("PLX".startsWith(upperCaseValue))
                    option.programmingLanguage = Option.ProgrammingLanguage.PLX;
                else if ("PLXASM".startsWith(upperCaseValue))
                    option.programmingLanguage = Option.ProgrammingLanguage.PLXASM;
                else if ("ML".startsWith(upperCaseValue))
                    option.programmingLanguage = Option.ProgrammingLanguage.ML;
                else
                    option.invalidValueError(param, start, value, p - start);
            }
            return option.tail;
        }
    },

    TEMPLATE("=string")
    {
        int setValue(char[] param, int start, int end, int p, int q, Option option)
        {
            option.templateName = option.getStringValue(param, q, end);
            return option.tail;
        }
    },

    TRACE("[=<none|conflicts|full>]")
    {
        int setBooleanValue(boolean flag, int p, Option option)
        {
            option.trace = flag ? Option.Trace.CONFLICTS : Option.Trace.NONE;
            return p;
        }

        int setValue(char[] param, int start, int end, int p, int q, Option option)
        {
            String value = option.getStringValue(param, q, end);
            int length = value.length();
            if (length > 0)
            {
                String upperCaseValue = value.toUpperCase();
                if ("NONE".startsWith(upperCaseValue))
                    option.trace = Option.Trace.NONE;
                else if ("CONFLICTS".startsWith(upperCaseValue))
                    option.trace = Option.Trace.CONFLICTS;
                else if ("FULL".startsWith(upperCaseValue))
                    option.trace = Option.Trace.FULL;
                else
                    option.invalidValueError(param, start, value, p - start);
            }
            else
            {
                option.reportMissingValue(param, start, end);
            }
            return option.tail;
        }
    },

    TRAILERS("=(string,string,string)")
    {
        int setValue(char[] param, int start, int end, int p, int q, Option option)
        {
            return setTripletValue(param, start, end, q, option, name(), option.trailerOptions);
        }
    },

    VARIABLES("[=<none|both|terminals|nt|nonterminals|non_terminals>]")
    {
        int setBooleanValue(boolean flag, int p, Option option)
        {
            option.variables = flag ? Option.Variables.BOTH : Option.Variables.NONE;
            return p;
        }

        int setValue(char[] param, int start, int end, int p, int q, Option option)
        {
            String value = option.getStringValue(param, q, end);
            if (value.length() > 0)
            {
                String upperCaseValue = value.toUpperCase();
                if ("NON".startsWith(upperCaseValue))
                    option.reportAmbiguousOption(param, start, end, true, "NONE, NON_TERMINALS");
                else if ("NONE".equals(upperCaseValue))
                    option.variables = Option.Variables.NONE;
                else if ("BOTH".startsWith(upperCaseValue))
                    option.variables = Option.Variables.BOTH;
                else if ("TERMINALS".startsWith(upperCaseValue))
                    option.variables = Option.Variables.TERMINALS;
                else if ("NT".equals(upperCaseValue) ||
                        "NONTERMINALS".startsWith(upperCaseValue) ||
                        "NON_TERMINALS".startsWith(upperCaseValue))
                    option.variables = Option.Variables.NON_TERMINALS;
                else
                    option.invalidValueError(param, start, value, p - start);
            }
            else
            {
                option.reportMissingValue(param, start, end);
            }
            return option.tail;
        }
    },

    VERBOSE
    {
        int setBooleanValue(boolean flag, int p, Option option)
        {
            option.verbose = flag;
            return p;
        }
    },

    VISITOR("[=<none|default|preorder>]")
    {
        int setBooleanValue(boolean flag, int p, Option option)
        {
            option.visitor = flag ? Option.Visitor.DEFAULT : Option.Visitor.NONE;
            return p;
        }

        int setValue(char[] param, int start, int end, int p, int q, Option option)
        {
            String value = option.getStringValue(param, q, end);
            if (value.length() > 0)
            {
                String upperCaseValue = value.toUpperCase();
                if ("NONE".startsWith(upperCaseValue))
                    option.visitor = Option.Visitor.NONE;
                else if ("DEFAULT".startsWith(upperCaseValue))
                    option.visitor = Option.Visitor.DEFAULT;
                else if ("PREORDER".startsWith(upperCaseValue))
                    option.visitor = Option.Visitor.PREORDER;
                else
                    option.invalidValueError(param, start, value, p - start);
            }
            else
            {
                option.reportMissingValue(param, start, end);
            }
            return option.tail;
        }
    },

    VISITOR_TYPE("=string", 2)
    {
        int setValue(char[] param, int start, int end, int p, int q, Option option)
        {
            option.visitorType = option.getStringValue(param, q, end);
            return option.tail;
        }
    },

    WARNINGS
    {
        int setBooleanValue(boolean flag, int p, Option option)
        {
            option.warnings = flag;
            return p;
        }
    },

    XREFERENCE
    {
        int setBooleanValue(boolean flag, int p, Option option)
        {
            option.xref = flag;
            return p;
        }
    };

    OptionEnum()
    {
        this(null, 1);
    }

    OptionEnum(String valueDesc)
    {
        this(valueDesc, 1);
    }

    OptionEnum(int priority)
    {
        this(null, priority);
    }

    OptionEnum(String valueDesc, int priority)
    {
        this.valueDesc      = valueDesc;
        this.priority       = priority;
        this.canonicalName  = name().replace('_', '-');
    }

    public int getPriority()
    {
        return priority;
    }

    public boolean isSwitchOption()
    {
        return (valueDesc == null || valueDesc.length() == 0 || valueDesc.charAt(0) == '[');
    }

    public boolean isValuedOption()
    {
        return (valueDesc != null && valueDesc.length() > 0);
    }

    public String getDescription()
    {
        return "-" + (valueDesc == null ? canonicalName.toLowerCase()
                                        : canonicalName.toLowerCase() + valueDesc);
    }

    int setBooleanValue(boolean flag, int p, Option option)
    {
        throw new UnsupportedOperationException();
    }

    int setValue(char[] param, int start, int end, int p, int q, Option option)
    {
        throw new UnsupportedOperationException();
    }

    private static int setTripletValue(char[] param, int start, int end,
            int q, Option option, String type, List<Option.BlockInfo> options)
    {
        int tail;
        if (q < end && param[q] == '(')
        {
            String filename = option.getStringValue(param, q + 1, end);
            String blockBegin = option.getStringValue(param, Option.cleanUp(param, option.tail, end), end);
            String blockEnd = option.getStringValue(param, Option.cleanUp(param, option.tail, end), end);

            //
            // Problem: When a quoted symbol is specified on the command line, the Windows OS
            // remove the surrounding quotes. Without the quote to delimit the block_end, GetStringValue
            // will stop after the ")". In this case, we remove the closing paren here and reset
            // the pointer so that it can be processed properly.
            //
            tail = option.tail;
            int blockEndLength = blockEnd.length();
            if (blockEndLength > 0 && blockEnd.charAt(blockEndLength - 1) == ')')
            {
                blockEnd = blockEnd.substring(0, blockEndLength - 1); // remove the trailing ")" from the block_end
                tail--; // move the pointer back to process the ")"
                blockEndLength--;
            }
            tail = Option.cleanUp(param, tail, end);
            if (tail < end && param[tail] == ')')
            {
                tail++;
                // the block-start and block-end symbol cannot be the null string
                if (blockBegin.length() > 0 && blockEndLength > 0)
                {
                    options.add(new Option.BlockInfo(
                            option.getTokenLocation(start, tail - start), filename, blockBegin, blockEnd));
                    return tail;
                }
            }
        }
        else
        {
            tail = Option.advancePastOption(param, start, end);
        }

        option.invalidTripletValueError(param, start, tail - start,
                type, "(filename,begin_block_marker,end_block_marker)");
        return tail;
    }
    
    private static int setProsthesesValue(char[] param, int start, int end, int p, int q, Option option)
    {
        String value = option.getStringValue(param, q, end);
        int length = value.length();
        if (length > 1)
        {
            String upperCaseValue = value.toUpperCase();
            if ("OPTIMIZED".startsWith(upperCaseValue))
                option.prostheses = Option.Prostheses.OPTIMIZED;
            else if ("MAXIMUM".startsWith(upperCaseValue))
                option.prostheses = Option.Prostheses.MAXIMUM;
            else if ("MINIMUM".startsWith(upperCaseValue))
                option.prostheses = Option.Prostheses.MINIMUM;
            else
                option.invalidValueError(param, start, value, p - start);
        }
        else if (length == 1)
        {
            char c = value.charAt(0);
            if (c == 'M' || c == 'm')
                option.reportAmbiguousOption(param, start, end, true, "MAXIMUM, MINIMUM");
            else if (c == 'O' || c == 'o')
                option.prostheses = Option.Prostheses.OPTIMIZED;
            else
                option.invalidValueError(param, start, value, p - start);
        }
        else
        {
            option.reportMissingValue(param, start, end);
        }
        return option.tail;
    }

    private final String    valueDesc;
    private final int       priority;
            final String    canonicalName;

}
